﻿#include "Sphere.h"

CSphere::CSphere(const Point3& vStaticCenter, double vRadius, shared_ptr<CMaterial> vMat)
	: m_CenterRay(vStaticCenter, Vec3(0, 0, 0)), m_Radius(std::fmax(0, vRadius)), m_pMat(vMat)
{
	auto RadiusVec = Vec3(vRadius, vRadius, vRadius);
	m_BBox = CAABB(vStaticCenter - RadiusVec, vStaticCenter + RadiusVec);
}

CSphere::CSphere(const Point3& vCenter1, const Point3& vCenter2, double vRadius, shared_ptr<CMaterial> vMat)
	:m_CenterRay(vCenter1, vCenter2 - vCenter1), m_Radius(std::fmax(0, vRadius)), m_pMat(vMat)
{
	auto RadiusVec = Vec3(vRadius, vRadius, vRadius);
	auto BBox1 = CAABB(m_CenterRay.at(0) - RadiusVec, m_CenterRay.at(0) + RadiusVec);
	auto BBox2 = CAABB(m_CenterRay.at(1) - RadiusVec, m_CenterRay.at(1) + RadiusVec);
	m_BBox = CAABB(BBox1, BBox2);
}

bool CSphere::hit(const CRay& vRay, CInterval vRayT, CHitRecord& vHitRecord) const
{
	Point3 CurCenter = m_CenterRay.at(vRay.time());
	Vec3 OC = CurCenter - vRay.origin();
	auto A = vRay.direction().length_squared();
	auto H = VecUtility::dot(vRay.direction(), OC);
	auto C = OC.length_squared() - m_Radius * m_Radius;
	auto Discriminant = H * H - A * C;

	if (Discriminant < 0.0) return false;

	auto Sqrtd = std::sqrt(Discriminant);

	auto Root = (H - Sqrtd) / A;//方程的解，即 t 的值
	if (!vRayT.surrounds(Root)) {
		Root = (H + Sqrtd) / A;
		if (!vRayT.surrounds(Root))
			return false;
	}

	vHitRecord.m_t = Root;
	vHitRecord.m_Point = vRay.at(vHitRecord.m_t);
	Vec3 OutwardNormal = (vHitRecord.m_Point - CurCenter) / m_Radius;
	vHitRecord.setFaceNormal(vRay, OutwardNormal);
	__getSphereUV(OutwardNormal, vHitRecord.m_u, vHitRecord.m_v);
	vHitRecord.m_pMat = m_pMat;

	return true;
}

void CSphere::__getSphereUV(const Point3& vPoint, double& u, double& v)
{
	//用 θ 和 ϕ 标识球面 uv 坐标
	auto Theta = std::acos(-vPoint.y());
	auto Phi = std::atan2(-vPoint.z(), vPoint.x()) + PI;

	u = Phi / (2 * PI);
	v = Theta / PI;
}
